A program originally written in a human-readable or high level source language is generally transformed into an executable program in a machine language by a process of compilation and linking. The resulting version of the program, termed binary code, may be executed by a processor-based system. Programs are commonly divided up for convenience, reusability, design complexity management, and other reasons, into sub-programs termed procedures. Procedures may be referred to by other names e.g., functions in languages such as C or C++. A program that is divided into procedures in a high level language version will generally be compiled and linked into a binary version of the program also with procedures that approximately correspond to the ones in the high level language version of the program. After compilation and linking, a program that is executing on a system typically uses a program stack to assist in the calling of procedures and in returning to the main flow of the program or calling procedure, as is well known in the art. In general, because procedure calls may be nested and the main program may be thought of as a main procedure, in the following, the terms “calling procedure” and “called procedure” are used without loss of generality. A procedure call must store a set of values related to the context of the call on the program stack, including the values of registers being used by the calling procedure such as the instruction pointer and other registers that may be over written by the execution of the called procedure. Other data values such as local variables of the calling procedure and parameters that are not to be modified by the called procedure may also be stored on the stack. All data related to a specific invocation of a specific procedure on the stack is termed its stack frame or its activation record.
In a typical run-time system for executing programs on a system, a procedure, on being called, allocates its stack frame on the program stack as one of its first sets of actions, and populates the stack frame with data which may be modified as the procedure executes. Prior to exit, it releases the allocated stack frame and updates the program stack pointer before executing a return. Thus, the program stack is managed in the normal process of program execution by the mechanisms of procedure call and return processing. However, sometimes program control may be transferred out of a procedure to another procedure without the normal processing of the procedure return mechanism.
This may occur in one instance when a procedure executes a long jump type instruction that causes program control to transfer to another procedure at a different level of the program stack without the execution of the intervening returns. In another instance, this may occur if an exception occurs within a procedure causing transfer of control to an exception handler at another level of the program stack, again without the stack being managed by a sequence of return calls. In yet another instance, this may happen if a debugger is being used to debug a program and control is transferred by a debugger external to the program from a point within a procedure to a point up the chain of calls that led to the current statement. In languages and runtime systems that support multithreading, the same type of phenomenon may be caused by thread termination.
When such a transfer of control from within a procedure occurs, for program execution to resume correctly at the new point to which control is transferred, the program stack needs to be unrolled or unwound, in a sense to simulate the normal return process as if it had occurred at the point at which control is transferred out of the procedure. In order for a proper unwinding of the program stack, some runtime systems provide specific support that is included in the executable image of a program. This is in the form of unwind information or unwind tables that allow a runtime system to correctly restore context after an exit from a procedure at a point other than a normal return.
Unwind information may be associated with each statement of a procedure from which such an exit can occur. In some instances, the unwind information may be associated with a block of statements or region of a procedure for which the unwind information is the same for all statements. In others, the unwind information may be different for different individual statements, or for different blocks of statements.
The usefulness of unwind information may be seriously compromised or eliminated by post-link program optimization. Post-link program optimization is a set of techniques intended to improve program performance e.g., in terms of execution time, by a variety of techniques that alter the code of the binary post-link version of the program without altering its other behavior, such as its input-output behavior. Among the well known techniques used by program optimization are procedure splitting, loop unrolling, and moving instructions out of loops. These techniques result in a new binary version of the program which differs from the original program in several ways, including by the altering or deletion of existing procedures, the addition of new procedures, the replication of statements, and the deletion of statements from the original version program. Unwind information associated with the procedures and statements of the original program will in general be of limited to no use in unwinding of the program stack of the optimized program.